1525. Задача группирования

 

Имеется множество из n целых чисел. Из любых k разных элементов Вы можете составить группу. Две группы считаются разными, если у них имеется хотя бы один не общий элемент. Например, если имеются 4 элемента a, b, c, d и Вам необходимо составить группы из двух элементов, то возможными допустимыми группами будут ab, ad, bc, cd. Систему групп будем называть полной для заданного k, если количество групп в ней максимально возможное. Например, для предыдущего примера {ab, bc, cd, bd, ad, ac} является полной системой групп.

Удобство полной системы групп будем вычислять следующим образом:

1.     Каждая группа делает свой вклад в систему – произведение чисел в группе;

2.     Вклады всех групп складываются;

3.     Удобство системы эквивалентно общему вкладу mod m, где m – ограничивающий параметр.

В нашем примере для k = 2 удобство равно F2 = (ab + bc + cd + bd + ad + ac) mod m. При k = 1 удобство равно F1 = (a + b + c + d) mod m.

Вам следует найти полную систему групп с максимальным удобством.

 

Вход. Каждый тест начинается двумя натуральными числами n (2 ≤ n ≤ 1000) и m (1 ≤ m < 231). Следующая строка содержит n натуральных чисел, каждое из которых не больше 1000. Последний тест содержит n = m = 0 и не обрабатывается.

 

Выход. Для каждого теста в отдельной строке вывести максимальное значение удобства среди всех полных систем групп.

 

Пример входа

Пример выхода

4 10

1 2 3 4

4 100

1 2 3 4

4 6

1 2 3 4

0 0

5

50

5

 

 

РЕШЕНИЕ

динамическое программирование

 

Анализ алгоритма

Пусть а1, a2, …, an – заданные n чисел. Обозначим через Fik (i ³ k) сумму всех возможных произведений по k чисел, взятых среди первых i чисел a1, …, ai. Построим следующую таблицу Fik:

 

 

Для четырех чисел соответственно получим:

·        F4,1 = a1 + a2 + a3 + a4;

·        F4,2 = a1a2 + a1a3 + a1a4 + a2a3 + a2a4 + a3a4;

·        F4,3 = a1a2a3 + a1a2a4 + a1a3a4 + a2a3a4;

·        F4,4 = a1a2a3a4;

 

Имеют место следующие рекуррентные соотношения:

Fi1 = F(i-1)1 + ai, Fii = F(i-1) (i-1) * ai, 1 £ i £ n

Fik = F(i-1)k + F(i-1) (k-1) * ai, 1 £ i £ n, 1 < k < i

 

Например,

·        F3,2 = F2,2 + F2,1 * a3 = a1a2 + (a1 + a2) * a3 = a1a2 + a1a3 + a2a3;

·        F4,3 = F3,3 + F3,2 * a4 = a1a2a3 + (a1a2 + a1a3 + a2a3) * a4 =

a1a2a3 + a1a2a4 + a1a3a4 + a2a3a4

 

Значения каждой следующей строки пересчитываются через значения предыдущей строки, поэтому в памяти достаточно хранить один линейный массив d размера 1000. При этом пересчет значений i - ой строки следует начинать с конца: сначала вычислить Fii, потом Fi(i-1) и так далее до Fi1. Все вычисления следует проводить по модулю m.

 

Пример

Рассмотрим первый тест. Построим две таблицы: вычисления во второй будут производиться по модулю m = 10, а в первой – нет.

 

 

Например,

·        F4,2 = F3,2 + F3,1 * 4 = 11 + 6 * 4 = 35;

·        F4,3 = F3,3 + F3,2 * 4 = 6 + 11 * 4 = 50;

 

Ответом является максимальное число в четвертой строке второй таблицы.

 

Реализация алгоритма

Объявим линейный массив d, в котором будут пересчитываться значения Fik.

 

long long d[1000];

 

Вводим количество чисел n и значение m. Для каждого входного теста изначально обнуляем массив d. Первое число a1 заносим в d[0].

 

while(scanf("%lld %lld",&n,&m), n + m > 0)

{

  memset(d,0,sizeof(d));

  scanf("%lld",&d[0]);

 

Вводим значение x = ai+1 (1 £ i < n) и пересчитываем значения Fik, k = i, i – 1, …, 1 по выше приведенным рекуррентным формулам. Все вычисления проводим по модулю m.

 

  for(i = 1; i < n; i++)

  {

    scanf("%lld",&x);

    d[i] = (d[i-1] * x) % m;

 

    for(j = i - 1; j > 0; j--)

      d[j] = (d[j-1] * x + d[j]) % m;

 

    d[0] = (d[0] + x) % m;

  }

 

Находим максимальное значение среди элементов массива d и заносим его в переменную res.

 

  res = 0;

  for(i = 0; i < n; i++)       

    if (d[i] > res) res = d[i];

 

Выводим результат.

 

  printf("%lld\n",res);

}